home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_400 / 428_02 / libsrc / menu.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-13  |  9.8 KB  |  413 lines

  1. /*
  2. ** menu.c
  3. **
  4. ** Pictor, Version 1.51, Copyright (c) 1992-94 SoftCircuits
  5. ** Redistributed by permission.
  6. */
  7.  
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <ctype.h>
  11. #include "pictor.h"
  12.  
  13.  
  14. #define STATE_WAIT         0x1000
  15. #define STATE_HILITE       0x1001
  16. #define STATE_RUN          0x1002
  17. #define STATE_CANCEL       0x1003
  18. #define STATE_LEFT         0x2000
  19. #define STATE_RIGHT        0x2001
  20. #define STATE_RUNCOMMAND   0x3000
  21.  
  22.  
  23. static int mainselect,subselect;
  24. static int num_menus,num_items,width;
  25.  
  26. int _PL_menurow = 1;
  27.  
  28. /*
  29. ** Returns the starting column for the given main menu item.
  30. */
  31. static int getmenucol(MAINMENU *menu,int item)
  32. {
  33.     int i,col = 3;
  34.  
  35.     for(i = 0;i < item;i++)
  36.         col += (hstrlen(menu[i].item) + 2);
  37.  
  38.     return(col);
  39.  
  40. } /* getmenucol */
  41.  
  42. /*
  43. ** Paints a hilite bar on the current submenu selection. Note that
  44. ** if the specified colors are the non-hilite colors, then the effect
  45. ** is that of removing the hilite bar.
  46. */
  47. static void hilite_submenu(SUBMENU *menu,int color,int hcolor,int col)
  48. {
  49.     setvpos(subselect + 2 + _PL_menurow,col - 1);
  50.     vrepa(color,width + 2);
  51.  
  52.     vcolor(color);
  53.     setvpos(subselect + 2 + _PL_menurow,col);
  54.     hputs(menu[subselect].item,hcolor);
  55.  
  56. } /* hilite_submenu */
  57.  
  58. /*
  59. ** Runs the specified submenu.
  60. */
  61. static int submenu(SUBMENU *menu,COLORSTRUCT *colors,int col)
  62. {
  63.     int state,state_value;
  64.     int i,key,alt_released = FALSE;
  65.  
  66.     /* get menu dimensions */
  67.     for(width = 0,num_items = 0;menu[num_items].item != NULL;num_items++) {
  68.         if(menu[num_items].item != (char *)-1) {
  69.             if(hstrlen(menu[num_items].item) > width)
  70.                 width = hstrlen(menu[num_items].item);
  71.         }
  72.     }
  73.     if(width == 0)    /* empty menu */
  74.         return STATE_WAIT;
  75.  
  76.     /* paint submenu */
  77.     wopen(_PL_menurow + 1,col - 2,num_items + 2,width + 4,colors->normal,
  78.         WO_STATICMEM | WO_SHADOW);
  79.     vcolor(colors->normal);
  80.     for(i = 0;menu[i].item != NULL;i++) {
  81.         if(menu[i].item != (char *)-1) {
  82.             setvpos(i + _PL_menurow + 2,col);
  83.             hputs(menu[i].item,colors->boldnormal);
  84.         }
  85.         else {  /* menu divider */
  86.             setvpos(i + _PL_menurow + 2,col - 2);
  87.             vputc('\xC7');
  88.             vrepc('\xC4',width + 2);
  89.             vputc('\xB6');
  90.         }
  91.     }
  92.  
  93.     state = STATE_HILITE;
  94.     subselect = state_value = 0;
  95.  
  96.     while(state != STATE_CANCEL) {
  97.         switch(state) {
  98.             case STATE_WAIT:
  99.                 if(kbdshift() & 0x08) {
  100.                     while((kbdshift() & 0x08) && !kbdready())
  101.                         ;
  102.  
  103.                     if(!kbdready() && alt_released) {
  104.                         state = STATE_CANCEL;
  105.                         state_value = STATE_WAIT;
  106.                     }
  107.                 }
  108.                 alt_released = TRUE;
  109.  
  110.                 if(kbdready()) {
  111.                     switch(key = kbdread()) {
  112.                         case DOWN_KEY:
  113.                         case SPACE_BAR:
  114.                             state = STATE_HILITE;
  115.                             state_value = subselect;
  116.                             do {
  117.                                 if(++state_value >= num_items)
  118.                                     state_value = 0;
  119.                             } while(menu[state_value].item == (char *)-1);
  120.                             break;
  121.                         case UP_KEY:
  122.                             state = STATE_HILITE;
  123.                             state_value = subselect;
  124.                             do {
  125.                                 if(--state_value < 0)
  126.                                     state_value = (num_items - 1);
  127.                             } while(menu[state_value].item == (char *)-1);
  128.                             break;
  129.                         case RIGHT_KEY:
  130.                             state = STATE_CANCEL;
  131.                             state_value = STATE_RIGHT;
  132.                             break;
  133.                         case LEFT_KEY:
  134.                             state = STATE_CANCEL;
  135.                             state_value = STATE_LEFT;
  136.                             break;
  137.                         case ENTER_KEY:
  138.                             state = STATE_CANCEL;
  139.                             state_value = STATE_RUNCOMMAND;
  140.                             break;
  141.                         case ESCAPE_KEY:
  142.                             state = STATE_CANCEL;
  143.                             state_value = STATE_CANCEL;
  144.                             break;
  145.                         case F1_KEY:
  146.                             if(_PL_helpfunc != NULL)
  147.                                 _PL_helpfunc(menu[subselect].helptopic);
  148.                             else beep();
  149.                             break;
  150.                         default:
  151.                             /* test for hotkey */
  152.                             if(isalnum(key = tolower(key & 0xFF))) {
  153.                                 for(i = 0;i < num_items;i++) {
  154.                                     if(key == tolower(gethotkey(menu[i].item))) {
  155.                                         state = STATE_CANCEL;
  156.                                         state_value = STATE_RUNCOMMAND;
  157.                                         subselect = i;
  158.                                         break;
  159.                                     }
  160.                                 }
  161.                             }
  162.                             if(state == STATE_WAIT) beep();
  163.                             break;
  164.                     }
  165.                 }
  166.                 break;
  167.             case STATE_HILITE:
  168.                 hilite_submenu(menu,colors->normal,colors->boldnormal,col);
  169.                 subselect = state_value;
  170.                 hilite_submenu(menu,colors->select,colors->boldselect,col);
  171.                 if(menu[subselect].description != NULL)
  172.                     statusbar(menu[subselect].description);
  173.                 state = STATE_WAIT;
  174.                 break;
  175.         }
  176.     }
  177.     wclose();
  178.  
  179.     return(state_value);
  180.  
  181. } /* submenu */
  182.  
  183. /*
  184. ** Displays the mainmenu across the top of the screen. Hotkeys
  185. ** are displayed bold if hilite is TRUE.
  186. */
  187. void showmenu(MAINMENU *menu,COLORSTRUCT *colors,int hilite)
  188. {
  189.     int i;
  190.  
  191.     setvpos(_PL_menurow,1);
  192.     vcolor(colors->normal);
  193.     vrepc(' ',_PL_columns);
  194.  
  195.     for(i = 0;menu[i].item != NULL;i++) {
  196.         setvpos(_PL_menurow,getmenucol(menu,i));
  197.         hputs(menu[i].item,(hilite) ? colors->boldnormal : colors->normal);
  198.     }
  199.  
  200. } /* showmenu */
  201.  
  202. /*
  203. ** Puts a hilite bar on the current main menu selection. Note that
  204. ** if normal attributes are passed, the effect is that of removing
  205. ** the hilite bar.
  206. */
  207. static void hilite_menu(MAINMENU *menu,int color,int hcolor)
  208. {
  209.     int col;
  210.  
  211.     col = getmenucol(menu,mainselect);
  212.  
  213.     setvpos(_PL_menurow,col - 1);
  214.     vrepa(color,hstrlen(menu[mainselect].item) + 2);
  215.  
  216.     if(hcolor != color) {
  217.         vcolor(color);
  218.         setvpos(_PL_menurow,col);
  219.         hputs(menu[mainselect].item,hcolor);
  220.     }
  221.  
  222. } /* hilite_menu */
  223.  
  224. /*
  225. ** Runs the specified main menu.
  226. */
  227. static int mainmenu(MAINMENU *menu,COLORSTRUCT *colors,
  228.     COLORSTRUCT *subcolors,int index)
  229. {
  230.     int i,key,state,state_value;
  231.  
  232.     if(index == -1) {
  233.         state = STATE_HILITE;
  234.         mainselect = state_value = 0;
  235.         showmenu(menu,colors,TRUE);
  236.     }
  237.     else {
  238.         state = STATE_RUN;
  239.         mainselect = state_value = index;
  240.     }
  241.  
  242.     /* count number of submenus */
  243.     for(num_menus = 0;menu[num_menus].item != NULL;num_menus++)
  244.         ;
  245.  
  246.     pushstatus();
  247.     pushcurs();
  248.     setcurs(_PL_rows + 1,1);
  249.  
  250.     while(state != STATE_CANCEL) {
  251.         switch(state) {
  252.             case STATE_WAIT:
  253.                 if(kbdshift() & 0x08) {
  254.                     state = STATE_CANCEL;
  255.                     state_value = STATE_WAIT;
  256.                 }
  257.                 else if(kbdready()) {
  258.                     switch(key = kbdread()) {
  259.                         case RIGHT_KEY:
  260.                         case SPACE_BAR:
  261.                             state_value = mainselect;
  262.                             if(++state_value >= num_menus)
  263.                                 state_value = 0;
  264.                             state = STATE_HILITE;
  265.                             break;
  266.                         case LEFT_KEY:
  267.                             state_value = mainselect;
  268.                             if(--state_value < 0)
  269.                                 state_value = (num_menus-1);
  270.                             state = STATE_HILITE;
  271.                             break;
  272.                         case ENTER_KEY:
  273.                         case DOWN_KEY:
  274.                         case UP_KEY:
  275.                             state_value = mainselect;
  276.                             state = STATE_RUN;
  277.                             break;
  278.                         case ESCAPE_KEY:
  279.                             state = STATE_CANCEL;
  280.                             state_value = STATE_CANCEL;
  281.                             break;
  282.                         case F1_KEY:
  283.                             if(_PL_helpfunc != NULL)
  284.                                 _PL_helpfunc(menu[mainselect].helptopic);
  285.                             else beep();
  286.                             break;
  287.                         default:
  288.                             /* test for hotkey */
  289.                             if(isalnum(key = tolower(key & 0xFF))) {
  290.                                 for(i = 0;i < num_menus;i++) {
  291.                                     if(key == tolower(gethotkey(menu[i].item))) {
  292.                                         state_value = i;
  293.                                         state = STATE_RUN;
  294.                                         break;
  295.                                     }
  296.                                 }
  297.                             }
  298.                             if(state == STATE_WAIT) beep();
  299.                             break;
  300.                     }
  301.                 }
  302.                 break;
  303.             case STATE_HILITE:
  304.                 hilite_menu(menu,colors->normal,colors->boldnormal);
  305.                 mainselect = state_value;
  306.                 hilite_menu(menu,colors->select,colors->boldselect);
  307.                 if(menu[mainselect].description != NULL)
  308.                     statusbar(menu[mainselect].description);
  309.                 state = STATE_WAIT;
  310.                 break;
  311.  
  312.             case STATE_RUN:
  313.                 while(state == STATE_RUN) {
  314.  
  315.                     /* remove bold hotkeys */
  316.                     showmenu(menu,colors,FALSE);
  317.  
  318.                     mainselect = state_value;
  319.                     hilite_menu(menu,colors->select,colors->select);
  320.  
  321.                     i = submenu(menu[mainselect].submenu,subcolors,
  322.                         getmenucol(menu,mainselect));
  323.  
  324.                     switch(i) {
  325.                         case STATE_RIGHT:
  326.                             if(++state_value >= num_menus)
  327.                                 state_value = 0;
  328.                             break;
  329.                         case STATE_LEFT:
  330.                             if(--state_value < 0)
  331.                                 state_value = (num_menus-1);
  332.                             break;
  333.                         case STATE_WAIT:
  334.                             showmenu(menu,colors,TRUE);
  335.                             state = STATE_HILITE;
  336.                             state_value = mainselect;
  337.                             break;
  338.                         default:
  339.                             state = STATE_CANCEL;
  340.                             state_value = i;
  341.  
  342.                     }
  343.                 }
  344.                 break;
  345.         }
  346.     }
  347.     popcurs();
  348.     popstatus();
  349.     if(state_value == STATE_RUNCOMMAND) {
  350.         menu[mainselect].submenu[subselect].function();
  351.         state_value = STATE_CANCEL;
  352.     }
  353.     showmenu(menu,colors,FALSE);
  354.  
  355.     return(state_value);
  356.  
  357. } /* mainmenu */
  358.  
  359. /*
  360. ** Waits for the next key press. If the key is used by the menu
  361. ** routines, it is handled appropriately. Otherwise this function
  362. ** returns the value of the key.
  363. **
  364. ** If a menu command is selected, the corresponding function is
  365. ** called from within the menu routines after which this routine
  366. ** will return 0.
  367. */
  368. int runmenu(MAINMENU *menu,COLORSTRUCT *colors,COLORSTRUCT *colors2)
  369. {
  370.     int i,state = STATE_WAIT,state_value = 0;
  371.     int alt_released = FALSE;
  372.  
  373.     while(state != STATE_CANCEL) {
  374.         switch(state) {
  375.             case STATE_WAIT:
  376.                 if(kbdshift() & 0x08) {
  377.                     showmenu(menu,colors,TRUE);
  378.                     while((kbdshift() & 0x08) && !kbdready())
  379.                         ;
  380.                     showmenu(menu,colors,FALSE);
  381.  
  382.                     if(alt_released) {
  383.                         state = STATE_CANCEL;
  384.                         state_value = 0;
  385.                     }
  386.                     else {
  387.                         state = STATE_RUN;   /* assume no key pressed */
  388.                         state_value = -1;
  389.                     }
  390.                 }
  391.                 if(kbdready()) {
  392.                     state = STATE_CANCEL;
  393.                     state_value = kbdread();
  394.                     for(i = 0;menu[i].item != NULL;i++) {
  395.                         if(getaltkey(gethotkey(menu[i].item)) == state_value) {
  396.                             state = STATE_RUN;
  397.                             state_value = i;
  398.                             break;
  399.                         }
  400.                     }
  401.                 }
  402.                 break;
  403.             case STATE_RUN:
  404.                 state = mainmenu(menu,colors,colors2,state_value);
  405.                 alt_released = TRUE;
  406.                 state_value = 0;
  407.                 break;
  408.         }
  409.     }
  410.     return(state_value);
  411.  
  412. } /* runmenu */
  413.